//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/05/01
// Design Name:
// Module Name: tm_ahb_if
// Project Name: wujian100
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// base ahb addr is 0x4002_0000  none offset
//////////////////////////////////////////////////////////////////////////////////

`include "ascon_define.v"



//定义hresp信号
`define OKAY            2'b00
`define ERROR           2'b01
`define RETRY           2'b10
`define SPLIT           2'b11

module `ASCON_AEAD_AHB_IF
   #(
    parameter MODE_SEL                           = 0
    )
    (
    //ahb总线信号
    input                                        tai_clk_i,
    input                                        tai_rst_n_i,
    input              [`AHB_BUS_ADDR_W - 1 : 0] tai_haddr_i,
    input                           [4  - 1 : 0] tai_hprot_i,                            //hprot[0]为0，代表是来自tee的访问信号，为1，代表是来自ree的访问信号
    input                           [1  - 1 : 0] tai_hsel_i,
    input                           [3  - 1 : 0] tai_hsize_i,
    input                           [2  - 1 : 0] tai_htrans_i,
    input              [`AHB_BUS_DATA_W - 1 : 0] tai_hwdata_i,
    input                           [1  - 1 : 0] tai_hwrite_i,

    output             [`AHB_BUS_DATA_W - 1 : 0] tai_hrdata_o,
    output                          [1  - 1 : 0] tai_hready_o,
    output                          [2  - 1 : 0] tai_hresp_o,
    output                          [1  - 1 : 0] tai_t2r_intr_o,
    //tx buf信号
    output reg         [`AHB_BUS_ADDR_W - 1 : 0] tx_buf_raddr_o,
    input              [`AHB_BUS_DATA_W - 1 : 0] tx_buf_rdat_i,

    //rx buf信号
    output reg                                   rx_buf_en_o,
    output reg                                   rx_buf_wen_o,
    output reg         [`AHB_BUS_ADDR_W - 1 : 0] rx_buf_waddr_o,
    output reg         [`AHB_BUS_DATA_W - 1 : 0] rx_buf_wdat_o,

    //ctrl regs信号
    output reg                                   ctrl_regs_en_o,
    output reg                                   ctrl_regs_wen_o,
    output reg         [`AHB_BUS_ADDR_W - 1 : 0] ctrl_regs_addr_o,
    output reg         [`AHB_BUS_DATA_W - 1 : 0] ctrl_regs_wdata_o,
    input              [`AHB_BUS_DATA_W - 1 : 0] ctrl_regs_rdata_i
    );



//////////////////////////////////////
//本地参数                           //
//////////////////////////////////////

localparam PORT_FIELD                            = 0;                                    //标志PORT信号的第几位是有效位

localparam IDLE                                  = `ASCON_AEAD_AHB_IF_FSM_NUM'b0000000;                 //空闲状态
localparam WRITE_CMD                             = `ASCON_AEAD_AHB_IF_FSM_NUM'b0000001;                 //写指令状态
localparam READ_CMD                              = `ASCON_AEAD_AHB_IF_FSM_NUM'b0000010;                 //读指令状态
localparam WITE_W_DAT                            = `ASCON_AEAD_AHB_IF_FSM_NUM'b0000100;                 //等待写数据状态
localparam WITE_R_DAT                            = `ASCON_AEAD_AHB_IF_FSM_NUM'b0001000;                 //等待读数据状态
localparam WRITE_DAT                             = `ASCON_AEAD_AHB_IF_FSM_NUM'b0010000;                 //写数据状态
localparam READ_DAT                              = `ASCON_AEAD_AHB_IF_FSM_NUM'b0100000;                 //读数据状态
localparam ERROR_RESP                            = `ASCON_AEAD_AHB_IF_FSM_NUM'b1000000;                  //违规请求响应状态

//////////////////////////////////////
//状态机信号                         //
//////////////////////////////////////

reg             [`ASCON_AEAD_AHB_IF_FSM_NUM-1:0] state_c;
reg             [`ASCON_AEAD_AHB_IF_FSM_NUM-1:0] state_n;

reg                    [`AHB_BUS_ADDR_W - 1 : 0] tai_haddr_r;
reg                    [`AHB_BUS_DATA_W - 1 : 0] tai_hwdata_r;
reg                                              tai_hready_r;
reg                                 [2  - 1 : 0] tai_hresp_r;
reg                    [`AHB_BUS_DATA_W - 1 : 0] tai_hrdata_r;

//////////////////////////////////////
//违规请求标志信号                    //
//////////////////////////////////////

wire                                             error_req_flag_w;                                      //错误请求标志线

//////////////////////////////////////
//读写使能信号                       //
//////////////////////////////////////

wire                                             w_en;                                                  //写使能标志
wire                                             r_en;                                                  //读使能标志
wire                                             en;                                                    //使能信号
wire                                             handshake;                                             //握手信号
wire                                     [2-1:0] addr_sel_w;
wire                                             t2r_rdy_w;
/************************************/
/*系统信号                           */
/************************************/

assign t2r_clk_w        = tai_clk_i;
assign t2r_rst_n_w      = tai_rst_n_i;

/************************************/
/*读写使能信号                       */
/************************************/
assign handshake        = ((tai_hsel_i == 1'b1)&&
                           (tai_hready_o == 1'b1)) ? 1'b1 : 1'b0;

assign w_en             = ((handshake == 1'b1)&&
                           (tai_hwrite_i == 1'b1)&&
                           (tai_htrans_i[1] == 1'b1)&&
                           (error_req_flag_w == 1'b0)) ? 1'b1 : 1'b0;

assign r_en             = ((handshake == 1'b1)&&
                           (tai_hwrite_i == 1'b0)&&
                           (tai_htrans_i[1] == 1'b1)&&
                           (error_req_flag_w == 1'b0)) ? 1'b1 : 1'b0;

assign en               = ((w_en == 1'b1)||(r_en == 1'b1)) ? 1'b1 : 1'b0;

/************************************/
/*违规请求标志                       */
/************************************/
// assign error_req_flag_w = ((((tai_hprot_i[PORT_FIELD] == 1'b1)&&(tai_hwrite_i == 1'b1)))&&//为来自ree的请求，且为写请求，属于违规操作
//                            (tai_hsel_i == 1'b1)&&(state_c == IDLE)) ? 1'b1 : 1'b0;       //选择信号为高，代表这些信号有效，上述表达式为真

generate

if (MODE_SEL == 0)                                                             //小信箱
assign error_req_flag_w = ((((tai_hprot_i[PORT_FIELD] == 1'b1)&&(tai_hwrite_i == 1'b1)))&&//为来自ree的请求，且为写请求，属于违规操作
                           (tai_hsel_i == 1'b1)&&(state_c == IDLE)) ? 1'b1 : 1'b0;       //选择信号为高，代表这些信号有效，上述表达式为真
else if (MODE_SEL == 1)                                                        //大信箱读写端
assign error_req_flag_w = ((((tai_hprot_i[PORT_FIELD] == 1'b1)))&&             //该通道为tee专用通道，只要是来自ree的访问都属于违规访问
                           (tai_hsel_i == 1'b1)&&(state_c == IDLE)) ? 1'b1 : 1'b0;       //选择信号为高，代表这些信号有效，上述表达式为真
else if (MODE_SEL == 2)                                                        //大信箱只读端
assign error_req_flag_w = ((((tai_hprot_i[PORT_FIELD] == 1'b0)&&(tai_hwrite_i == 1'b1)))&&//为来自tee的请求，且为写请求，属于违规操作
                           (((tai_hprot_i[PORT_FIELD] == 1'b0)))&&             //该通道为ree专用通道，只要是来自tee的访问都属于违规访问
                           (tai_hsel_i == 1'b1)&&(state_c == IDLE)) ? 1'b1 : 1'b0;       //选择信号为高，代表这些信号有效，上述表达式为真
else                                                                           //默认情况
assign error_req_flag_w = ((((tai_hprot_i[PORT_FIELD] == 1'b1)&&(tai_hwrite_i == 1'b1)))&&//为来自ree的请求，且为写请求，属于违规操作
                           (tai_hsel_i == 1'b1)&&(state_c == IDLE)) ? 1'b1 : 1'b0;       //选择信号为高，代表这些信号有效，上述表达式为真
endgenerate

/************************************/
/*状态机                            */
/************************************/

/*************part 1*************/
always@(posedge tai_clk_i or negedge tai_rst_n_i)                              //当前状态
begin : STATE_C_PROG
  if (tai_rst_n_i == 1'b0)
    state_c             <= {(`ASCON_AEAD_AHB_IF_FSM_NUM){1'b0}};
  else
    state_c             <= state_n;
end

/*************part 2*************/
always@(*)                                                                     //状态转换
begin : STATE_N_PROG
  case (state_c)
	IDLE        :
    begin
	  if (error_req_flag_w == 1'b1)                                            //如果出现违规请求
	    state_n         = ERROR_RESP;                                          //转换到错误响应状态
	  else if (w_en == 1'b1)                                                   //如果写使能
	    state_n         = WRITE_CMD;                                           //转换到写命令状态
	  else if (r_en == 1'b1)                                                   //如果读使能
	    state_n         = READ_CMD;                                            //转换到读命令状态
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //空闲状态
	end
    WRITE_CMD   :
	begin
	  if (t2r_rdy_w == 1'b0)                                                   //如果从机没有准备好
	    state_n         = WITE_W_DAT;                                          //则等待写数据
	  else if (t2r_rdy_w == 1'b1)                                              //如果从机准备好
	    state_n         = WRITE_DAT;                                           //写数据
	  else                                                                     //其它情况
	    state_n         = ERROR_RESP;                                          //返回错误响应
	end
    READ_CMD    :
	begin
	  if (t2r_rdy_w == 1'b0)                                                   //如果从机没有准备好
	    state_n         = WITE_R_DAT;                                          //则等待读数据
	  else if (t2r_rdy_w == 1'b1)                                              //如果从机准备好
	    state_n         = READ_DAT;                                            //读数据
	  else                                                                     //其它情况
	    state_n         = ERROR_RESP;                                          //返回错误响应
	end
    WITE_W_DAT  :
	begin
      if (t2r_rdy_w == 1'b0)                                                   //如果从机没有准备好
	    state_n         = WITE_W_DAT;                                          //则等待写数据
	  else                                                                     //从机准备好
	    state_n         = WRITE_DAT;                                           //写数据
	end
    WITE_R_DAT  :
	begin
      if (t2r_rdy_w == 1'b0)                                                   //如果从机没有准备好
	    state_n         = WITE_R_DAT;                                          //则等待读数据
	  else                                                                     //从机准备好
	    state_n         = READ_DAT;                                            //读数据
	end
    WRITE_DAT   :
    begin
      if (w_en == 1'b1)                                                        //如果在写数据的时候主机已发送下一组写指令
	    state_n         = WRITE_CMD;                                           //转换到写指令
	  else if (r_en == 1'b1)                                                   //如果在写数据的时候主机已发送下一组读指令
	    state_n         = READ_CMD;                                            //转换到读指令
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //转换到空闲状态
	end
    READ_DAT    :
    begin
      if (r_en == 1'b1)                                                        //如果在写数据的时候主机已发送下一组读指令
	    state_n         = READ_CMD;                                            //转换到读指令
	  else if (w_en == 1'b1)                                                   //如果在写数据的时候主机已发送下一组写指令
	    state_n         = WRITE_CMD;                                           //转换到写指令
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //转换到空闲状态
	end
    ERROR_RESP  :
    begin
      if (r_en == 1'b1)                                                        //如果在写数据的时候主机已发送下一组读指令
	    state_n         = READ_CMD;                                            //转换到读指令
	  else if (w_en == 1'b1)                                                   //如果在写数据的时候主机已发送下一组写指令
	    state_n         = WRITE_CMD;                                           //转换到写指令
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //转换到空闲状态
	end
	default     :
      state_n           = IDLE;
  endcase
end

/*************part 3*************/

always@(posedge tai_clk_i or negedge tai_rst_n_i)
begin : TAI_HADDR_R_PROG
  if (tai_rst_n_i == 1'b0)                                                     //复位信号有效
    tai_haddr_r         <= {(32){1'b0}};                                       //复位
  else if ((state_c == IDLE)&&(en == 1'b1))                                    //当前为空闲状态，并且有指令路由过来时
    tai_haddr_r         <= tai_haddr_i;                                        //将指令信号寄存
  else                                                                         //其它情况
    tai_haddr_r         <= tai_haddr_r;                                        //保持
end

always@(*)
begin : TAI_HWDATA_R_PROG
  if (state_c == WRITE_DAT)                                                    //当前为写指令，并且下一个状态为写数据
    tai_hwdata_r         = tai_hwdata_i;                                       //将指令信号寄存
  else                                                                         //其它情况
    tai_hwdata_r         = {(32){1'b0}};                                       //无效
end

always@(*)
begin : TAI_HREADY_R_PROG
  if ((state_c == IDLE)||                                                      //空闲状态
      (state_c == ERROR_RESP)||                                                //当前为错误响应状态，立即响应错误，ahb_rdy为高
	  (state_c == WRITE_DAT)||
	  (state_c == READ_DAT))
    tai_hready_r        = 1'b1;                                                //rdy有效
  else                                                                         //其它情况
    tai_hready_r        = 1'b0;                                                //rdy无效
end

always@(*)
begin : TAI_HRESP_R_PROG
  if (state_c == ERROR_RESP)                                                   //当前为响应错误状态
    tai_hresp_r         = `ERROR;                                              //响应错误
  else                                                                         //其它情况
    tai_hresp_r         = `OKAY;                                               //传输正确
end


/************************************/
/*AHB写控制信号                      */
/************************************/

assign addr_sel_w       = tai_haddr_r[11:10];

always @(*)
begin : ADDR_PROG
  case (addr_sel_w)
    2'b00 : // rx_buf
    begin
      rx_buf_waddr_o    = tai_haddr_r;
      tx_buf_raddr_o    = `AHB_BUS_ADDR_W'b0;
      ctrl_regs_addr_o  = `AHB_BUS_ADDR_W'b0;
    end
    2'b01 : //ctrl_regs
    begin
      rx_buf_waddr_o    = `AHB_BUS_ADDR_W'b0;
      tx_buf_raddr_o    = `AHB_BUS_ADDR_W'b0;
      ctrl_regs_addr_o  = tai_haddr_r;
    end
    2'b10 : // tx_buf
    begin
      rx_buf_waddr_o    = `AHB_BUS_ADDR_W'b0;
      tx_buf_raddr_o    = tai_haddr_r;
      ctrl_regs_addr_o  = `AHB_BUS_ADDR_W'b0;
    end
    default:
    begin
      rx_buf_waddr_o    = `AHB_BUS_ADDR_W'b0;
      tx_buf_raddr_o    = `AHB_BUS_ADDR_W'b0;
      ctrl_regs_addr_o  = `AHB_BUS_ADDR_W'b0;
    end
  endcase
end

always @(*)
begin : EN_PROG
  case (addr_sel_w)
    2'b00 :
    begin
      rx_buf_en_o       = (state_c == WRITE_DAT) ? 1'b1 : 1'b0;
      ctrl_regs_en_o    = 1'b0;
    end
    2'b01 :
    begin
      rx_buf_en_o       = 1'b0;
      ctrl_regs_en_o    = ((state_c == WRITE_DAT)||(state_c == READ_DAT)) ? 1'b1 : 1'b0;
    end
    2'b10 :
    begin
      rx_buf_en_o       = 1'b0;
      ctrl_regs_en_o    = 1'b0;
    end
    default:
    begin
      rx_buf_en_o       = 1'b0;
      ctrl_regs_en_o    = 1'b0;
    end
  endcase
end

always @(*)
begin : WEN_PROG
  case (addr_sel_w)
    2'b00 :
    begin
      rx_buf_wen_o      = (state_c == WRITE_DAT) ? 1'b1 : 1'b0;
      ctrl_regs_wen_o   = 1'b0;
    end
    2'b01 :
    begin
      rx_buf_wen_o      = 1'b0;
      ctrl_regs_wen_o   = (state_c == WRITE_DAT) ? 1'b1 : 1'b0;
    end
    2'b10 :
    begin
      rx_buf_wen_o      = 1'b0;
      ctrl_regs_wen_o   = 1'b0;
    end
    default:
    begin
      rx_buf_wen_o      = 1'b0;
      ctrl_regs_wen_o   = 1'b0;
    end
  endcase
end

always @(*)
begin : RDATA_PROG
  case (addr_sel_w)
    2'b00 :
      tai_hrdata_r      = `AHB_BUS_DATA_W'b0;
    2'b01 :
      tai_hrdata_r      = ctrl_regs_rdata_i;
    2'b10 :
      tai_hrdata_r      = tx_buf_rdat_i;
    default:
      tai_hrdata_r      = `AHB_BUS_DATA_W'b0;
  endcase
end

always @(*)
begin : WDATA_PROG
  case (addr_sel_w)
    2'b00 :
    begin
      rx_buf_wdat_o     = tai_hwdata_r;
      ctrl_regs_wdata_o = `AHB_BUS_DATA_W'b0;
    end
    2'b01 :
    begin
      rx_buf_wdat_o     = `AHB_BUS_DATA_W'b0;
      ctrl_regs_wdata_o = tai_hwdata_r;
    end
    2'b10 :
    begin
      rx_buf_wdat_o     = `AHB_BUS_DATA_W'b0;
      ctrl_regs_wdata_o = `AHB_BUS_DATA_W'b0;
    end
    default:
    begin
      rx_buf_wdat_o     = `AHB_BUS_DATA_W'b0;
      ctrl_regs_wdata_o = `AHB_BUS_DATA_W'b0;
    end
  endcase
end

assign t2r_rdy_w        = 1'b1;
/************************************/
/*AHB读控制信号                      */
/************************************/

//在接收到违规请求之后，下一个时钟周期返回错误响应
assign tai_hrdata_o     = tai_hrdata_r;                                        //读数据信号由状态机控制
assign tai_hresp_o      = tai_hresp_r;                                         //响应信号的生成由状态机控制，读写都需要
assign tai_hready_o     = tai_hready_r;                                        //将总线上的ready信号与从机的ready信号隔离，通过状态机单独控制

assign tai_t2r_intr_o   = 1'b0;

endmodule